#==============================================================================
#
#  $Id: rsh.py,v 1.4 2001/07/12 23:19:32 mike Exp $
#
"""
   Remote shell module.  Allows dopy method invocations via remote shell,
   secure shell, or any other means of running a single program.
"""
#
#  Copyright (C) 2000 Michael A. Muller
#
#  Permission is granted to use, modify and redistribute this code,
#  providing that the following conditions are met:
#
#  1) This copyright/licensing notice must remain intact.
#  2) If the code is modified and redistributed, the modifications must 
#  include documentation indicating that the code has been modified.
#  3) The author(s) of this code must be indemnified and held harmless
#  against any damage resulting from the use of this code.
#
#  This code comes with ABSOLUTELY NO WARRANTEE, not even the implied 
#  warrantee of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
#
#  $Log: rsh.py,v $
#  Revision 1.4  2001/07/12 23:19:32  mike
#  Added initial support for non-threaded operation.
#
#  Revision 1.3  2001/02/05 17:46:38  mike
#  Fixed copyright dates.
#
#  Revision 1.2  2000/07/29 21:15:48  mike
#  Added docs.
#
#
#==============================================================================


import sys, time, select
from pickle import Pickler, Unpickler
import dopy
import popen2, thread

class StdStream:
   
   def __init__(self, stdin, stdout):
      self.stdin = stdin
      self.stdout = stdout
   
   def fileno(self):
      return self.stdin.fileno()
   
   def write(self, data):
      self.stdout.write(data)
      self.stdout.flush()
   
   def read(self, *parms):
      return apply(self.stdin.read, parms)
   
   def readline(self):
      return self.stdin.readline()

class StdStreamReader:
   
   def isActive(self):
      return 1
   
   def shutdown(self):
      pass

class Protocol(StdStreamReader, dopy.Protocol):
   
   def __init__(self, cmd, ioTuple = None):
      self.cmd = cmd
      if not ioTuple:
         self.src, self.dest = popen2.popen2(self.cmd)
      else:
         self.src, self.dest = ioTuple
      
      hub = dopy.getHub()
      if hub.isThreaded():
         self.__lk = thread.allocate_lock()
      else:
         self.__lk = None
      
      hub.addProtocol(self)
   
   def send(self, obj):
      if self.__lk:
         self.__lk.acquire()
      try:
         Pickler(self.dest).dump(obj)
         self.dest.flush()
      finally:
         if self.__lk:
            self.__lk.release()
   
   def getNext(self):
      try:
         rdx, wrx, erx = select.select([self.src], [], [self.src])
         evt =  Unpickler(self.src).load()
      except EOFError:
         _finished.release()
         return None
      return evt

   def getProtocolId(self):
      return 'dopyrsh:%s' % self.cmd

   def fileno(self):
      return self.src.fileno()

class Server(StdStreamReader, dopy.ProtocolServer):
   
   def __init__(self):
      self.__gotConnection = 0
   
   def acceptConnection(self):
      if self.__gotConnection:
         while 1:
            time.sleep(3600)
      else:
         self.__gotConnection = 1
         return Protocol('', (sys.stdin, sys.stdout))

   def isSingleConnection(self):
      return 1

def makeServer():
   hub = dopy.getHub()
   hub.addServer(Server())

def _factory(id):
   return Protocol(id[1])
      
def remote(cmd, key):
   hub = dopy.getHub()
   prot = hub.getProtocol('dopyrsh:%s' % cmd)
   return dopy.DynamicRemoteObject(prot, key)   

dopy.protocolFactory.register('dopyrsh', _factory)

_finished = thread.allocate_lock()
_finished.acquire()
def wait():
   _finished.acquire()

   